package edu.nf.relaxenjoy.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import edu.nf.relaxenjoy.common.constant.Constant;
import edu.nf.relaxenjoy.common.constant.platform.PlatformConstant;
import edu.nf.relaxenjoy.common.constant.platform.RabbitMqConstant;
import edu.nf.relaxenjoy.common.exception.ErrorsEnum;
import edu.nf.relaxenjoy.common.exception.CommonException;
import edu.nf.relaxenjoy.common.util.ConvertUtils;
import edu.nf.relaxenjoy.common.util.PageUtils;
import edu.nf.relaxenjoy.common.util.RedisUtils;
import edu.nf.relaxenjoy.common.util.WebUtils;
import edu.nf.relaxenjoy.domain.entity.*;
import edu.nf.relaxenjoy.mapper.*;
import edu.nf.relaxenjoy.service.*;
import edu.nf.relaxenjoy.domain.dto.AlbumRelationDTO;
import edu.nf.relaxenjoy.domain.dto.PostDTO;
import edu.nf.relaxenjoy.domain.vo.BrowseRecordDTO;
import edu.nf.relaxenjoy.domain.vo.PostVo;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @author zhu
 * @date 2024-12-10
 */
@Service("postService")
@RequiredArgsConstructor
@Slf4j
public class PostServiceImpl implements PostService {

    private final PostMapper postMapper;

    private final UserMapper userMapper;

    private final AlbumMapper albumMapper;

    private final AlbumRelationMapper albumRelationMapper;

    private final AlbumRelationService albumRelationService;

    private final CategoryMapper categoryMapper;

    private final TagMapper tagMapper;

    private final TagRelationMapper tagRelationMapper;

    private final AgreeCollectMapper agreeCollectMapper;

    private final PlatformProducer platformProducer;

    private final PlatformDataToCache platformDataToCache;

    private final RedisUtils redisUtils;

    private final EsService esService;

    private final MinioService minioService;

    @Override
    public void addBrowseRecord(BrowseRecordDTO browseRecordDTO) {
        String userBrowseRecordKey = PlatformConstant.BR_IMG_KEY + browseRecordDTO.getUid();
        if (Boolean.TRUE.equals(redisUtils.hasKey(userBrowseRecordKey))) {
            List<String> objs = redisUtils.lRange(userBrowseRecordKey, 0, -1);
            for (String s : objs) {
                PostVo postVo = JSON.parseObject(s, PostVo.class);
                if (postVo.getId().equals(browseRecordDTO.getMid())) {
                    redisUtils.lRemove(userBrowseRecordKey, 0, s);
                    break;
                }
            }
        }

        Post post = postMapper.getById(browseRecordDTO.getMid());
        PostVo postVo = ConvertUtils.sourceToTarget(post, PostVo.class);

        User user = userMapper.getUserByUserId(post.getUserId());
        postVo.setUsername(user.getUsername());
        postVo.setNickName(user.getNickname());
        postVo.setAvatar(user.getAvatar());

        redisUtils.lLeftPush(userBrowseRecordKey, JSON.toJSONString(postVo));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteImgs(List<String> idList, String uid) {
        if (idList.isEmpty()) {
            return;
        }
        //删除图片
        List<Post> postsEntityList = postMapper.listByIds(idList.stream().map(Long::valueOf).toList(), null);
        List<AlbumRelation> albumRelationList;

        //删除图片收藏
//        agreeCollectMapper.removeBatch(idList.stream().map(Long::valueOf).toList(), 3);

        //---
        for (Post model : postsEntityList) {
            //图片绑定专辑
            albumRelationList = albumRelationMapper.getListByMid(model.getId());

            //所有绑定的专辑
            List<Long> albumIds = albumRelationList.stream().map(AlbumRelation::getAid).collect(Collectors.toList());
            List<Album> albumList = albumMapper.listByIds(albumIds);
            HashMap<Long, Album> albumMap = new HashMap<>();
            albumList.forEach(item -> {
                albumMap.put(item.getId(), item);
            });

            if (String.valueOf(model.getUserId()).equals(uid)) {

                for (AlbumRelation albumRelationModel : albumRelationList) {
                    Album albumEntity = albumMap.get(albumRelationModel.getAid());

                    if (albumEntity.getImgCount() >= model.getCount()) {
                        albumEntity.setImgCount(albumEntity.getImgCount() - model.getCount());
                        albumMapper.updateById(albumEntity);
                    }

                    albumRelationMapper.removeOne(albumEntity.getId(), model.getId());
                    //删除图片与标签的绑定关系
                    tagRelationMapper.removeByMid(model.getId());


                    //删除推荐系统中缓存的数据
                    String recommendKey = PlatformConstant.RECOMMEND + model.getId();
                    if (Boolean.TRUE.equals(redisUtils.hasKey(recommendKey))) {
                        redisUtils.delete(recommendKey);
                    }

                    String imgDetailStateKey = PlatformConstant.POST_STATE + model.getId();
                    if (Boolean.TRUE.equals(redisUtils.hasKey(imgDetailStateKey))) {
                        redisUtils.delete(imgDetailStateKey);
                    }

                    //删除hmap中的图片信息
                    redisUtils.hDelete(PlatformConstant.POST_LIST_KEY, String.valueOf(model.getId()));

                    if (model.getStatus() == 1) {
                        //删除es中的数据
                        try {
                            esService.delData(String.valueOf(model.getId()));
                        } catch (Exception e) {
                            throw new CommonException(ErrorsEnum.FAIL);
                        }
                    }

                    //删除minio存储中的图片
                    List<String> fileNames = JSON.parseArray(model.getImages().replace("\\\"", "\""), String.class);

                    for (String item : fileNames) {
                        if (WebUtils.isHttpUrl(item)) {
                            minioService.deleteFile(item);
                        }
                    }
                    postMapper.remove(model);
                }
            } else {
                //找到当前图片所属专辑
                for (AlbumRelation albumRelationModel : albumRelationList) {
                    Album albumEntity = albumMap.get(albumRelationModel.getAid());
                    if (String.valueOf(albumEntity.getUid()).equals(uid)) {
                        albumRelationMapper.removeOne(albumRelationModel.getAid(), model.getId());
                    }
                }
            }
        }
    }

    @Override
    public PageInfo<PostVo> getPage(Long pageNum, Long pageSize) {
        // 开始分页
        PageHelper.startPage(pageNum.intValue(), pageSize.intValue());

        // 查询 Post 列表
        List<Post> posts = postMapper.postList(pageNum, pageSize, 1);

        // 获取分页信息
        PageInfo<Post> postPageInfo = new PageInfo<>(posts);

        // 提取用户 ID 列表
        List<Long> uids = posts.stream().map(Post::getUserId).collect(Collectors.toList());

        // 查询用户列表
        Map<Long, User> userMap = new HashMap<>();

        if (!uids.isEmpty()) {
            // 仅在 uids 不为空时执行查询
            List<User> userList = userMapper.listByIds(uids);
            userList.forEach(item -> userMap.put(item.getUserId(), item));
        }

        // 转换 Post 到 PostVo
        List<PostVo> postVoList = new ArrayList<>();
        PostVo postVo;
        User user;
        for (Post post : posts) {
            postVo = ConvertUtils.sourceToTarget(post, PostVo.class);
            // 通过替换来去掉转义字符
            String imagesString = post.getImages().replace("\\\"", "\"");
            List<String> imgList = JSON.parseArray(imagesString, String.class);
            if (!imgList.isEmpty()) {
                postVo.setImages(imgList);
            }
            // 设置用户信息
            user = userMap.get(post.getUserId());
            if (user != null) {
                postVo.setUserId(user.getUserId());
                postVo.setUsername(user.getUsername());
                postVo.setAvatar(user.getAvatar());
            }

            // 添加转换后的 PostVo 到列表
            postVoList.add(postVo);
        }

        // 构造 PageInfo<PostVo> 对象
        PageInfo<PostVo> postVoPageInfo = new PageInfo<>(postVoList);
        // 设置总记录数
        postVoPageInfo.setTotal(postPageInfo.getTotal());
        postVoPageInfo.setPageNum(postPageInfo.getPageNum());
        postVoPageInfo.setPageSize(postPageInfo.getPageSize());
        postVoPageInfo.setIsFirstPage(postPageInfo.isIsFirstPage());
        postVoPageInfo.setIsLastPage(postPageInfo.isIsLastPage());
        postVoPageInfo.setNavigatePages(postPageInfo.getNavigatePages());
        postVoPageInfo.setPages(postPageInfo.getPages());
        // 设置结果列表
        postVoPageInfo.setList(postVoList);

        return postVoPageInfo;
    }

    @Override
    public PageInfo<PostVo> getAllImgByAlbum(Long pageNum, Long pageSize, String albumId, Integer type) {
        // 开始分页
        PageHelper.startPage(pageNum.intValue(), pageSize.intValue());

        // 查询 AlbumRelation 列表
        List<AlbumRelation> albumRelationList = albumRelationMapper.getPage(pageNum, pageSize, Long.valueOf(albumId));

        // 获取分页信息
        PageInfo<AlbumRelation> albumPageInfo = new PageInfo<>(albumRelationList);
        long total = albumPageInfo.getTotal();

        // 提取中间表中的 mid 列表
        List<Long> mids = albumRelationList.stream().map(AlbumRelation::getMid).collect(Collectors.toList());

        List<Post> postList;
        if (type == 0) {
            // 查询符合条件的 ImgDetail
            postList = postMapper.listByIds(mids, 1);
        } else {
            // 根据 ids 查询 ImgDetail
            postList = postMapper.listByIds(mids, null);
        }

        // 提取用户 ID 列表
        List<Long> uids = postList.stream().map(Post::getUserId).collect(Collectors.toList());
        List<User> userList = userMapper.listByIds(uids);

        // 构建索引 Map
        Map<Long, Post> postMap = postList.stream()
                .collect(Collectors.toMap(Post::getId, item -> item));
        Map<Long, User> userMap = userList.stream()
                .collect(Collectors.toMap(User::getUserId, item -> item));

        // 创建结果集合
        List<PostVo> postVoList = new ArrayList<>();
        Post post;
        PostVo postVo;
        for (AlbumRelation model : albumRelationList) {
            post = postMap.get(model.getMid());
            if (post != null) {
                User user = userMap.get(post.getUserId());
                postVo = ConvertUtils.sourceToTarget(post, PostVo.class);
                if (user != null) {
                    postVo.setUsername(user.getUsername());
                    postVo.setAvatar(user.getAvatar());
                }
                postVoList.add(postVo);
            }
        }

        // 构建最终 PageInfo 对象
        PageInfo<PostVo> resPage = new PageInfo<>(postVoList);
        resPage.setTotal(total);
        return resPage;
    }

    @Override
    public PostVo getImgDetail(String id) {
        Post post = postMapper.getById(Long.valueOf(id));

        if(post.getViewCount() <= 100){
            post.setViewCount(post.getViewCount() + 1);
            platformProducer.sendMessage(RabbitMqConstant.POST_STATE_EXCHANGE,RabbitMqConstant.POST_STATE_QUEUE,post);
        } else {
            String postStateKey = RabbitMqConstant.POST_STATE_KEY + post.getId();
            platformDataToCache.postDataToCache(post, postStateKey, 3, 1);
        }

        List<String> imgList = JSON.parseArray(post.getImages().replace("\\\"", "\""), String.class);
        User user = userMapper.getUserByUserId(post.getUserId());

        List<Long> categoryIds = new ArrayList<>();
        categoryIds.add(post.getCategoryId());
        categoryIds.add(post.getCategoryPid());
        List<Category> categoryList = categoryMapper.listByIds(categoryIds);
        HashMap<Integer, Category> categoryMap = new HashMap<>();

        categoryList.forEach(item -> {
            if (item.getPid() == 0) {
                categoryMap.put(0, item);
            } else {
                categoryMap.put(1, item);
            }
        });

        PostVo postVo = ConvertUtils.sourceToTarget(post, PostVo.class);
        postVo.setImages(imgList);
        postVo.setCategoryId(categoryMap.get(1).getId());
        postVo.setCategoryName(categoryMap.get(1).getName());
        postVo.setCategoryPid(categoryMap.get(0).getId());
        postVo.setCategoryPName(categoryMap.get(0).getName());
        postVo.setUserId(user.getUserId());
        postVo.setUsername(user.getUsername());
        postVo.setNickName(user.getNickname());
        postVo.setAvatar(user.getAvatar());
        postVo.setTime(post.getUpdateDate());

        //得到当前图像的所有标签
        List<TagRelation> tagRelationList = tagRelationMapper.getList(post.getId());
        List<Long> tids = tagRelationList.stream().map(TagRelation::getTid).collect(Collectors.toList());

        if (!tids.isEmpty()) {
            List<Tag> tagList = tagMapper.listByIds(tids);
            postVo.setTagList(tagList);
        }

        //得到专辑
        List<Album> albumList = albumMapper.getAllAlbum();
        //图片绑定多个专辑
        List<AlbumRelation> albumRelationList = albumRelationMapper.getListByMid(post.getId());
        HashMap<Long, Album> albumMap = new HashMap<>();
        albumList.forEach(item -> {
            albumMap.put(item.getId(), item);
        });

        for (AlbumRelation item : albumRelationList) {
            if (albumMap.containsKey(item.getAid())) {
                Album album = albumMap.get(item.getAid());
                postVo.setAlbum(album);
                break;
            }
        }

        return postVo;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long publish(PostDTO postDTO) {
        Post post = ConvertUtils.sourceToTarget(postDTO, Post.class);
        post.setImages(postDTO.getImgsUrl());
        post.setCreateDate(new Date());
        post.setUpdateDate(new Date());
        post.setCollectionCount(0L);
        post.setCommentCount(0L);
        post.setAgreeCount(0L);
        post.setViewCount(0L);
        // 添加
        postMapper.insert(post);
        Post currPost = postMapper.getPost(postDTO);
        post.setId(currPost.getId());

        AlbumRelation albumRelation = new AlbumRelation();
        albumRelation.setAid(postDTO.getAlbumId());
        albumRelation.setMid(post.getId());
        albumRelationMapper.insert(albumRelation);

        Album album = albumMapper.getById(postDTO.getAlbumId());
        album.setImgCount(postDTO.getCount() + album.getImgCount());
        albumMapper.updateById(album);


        List<TagRelation> tagRelationList = new ArrayList<>();
        for (Tag tag : postDTO.getTags()) {
            long id = tagMapper.getByName(tag.getName()).getId();
            TagRelation tagRelationEntity = new TagRelation();
            tagRelationEntity.setMid(post.getId());
            tagRelationEntity.setTid(id);
            tagRelationList.add(tagRelationEntity);
        }

        tagRelationMapper.insertBatch(tagRelationList);


        User user = userMapper.getUserByUserId(post.getUserId());
        user.setTrendCount(user.getTrendCount() + 1);
        platformProducer.sendMessage(RabbitMqConstant.USER_STATE_EXCHANGE, RabbitMqConstant.USER_STATE_KEY, user);

        PostVo postVo = ConvertUtils.sourceToTarget(post, PostVo.class);
        postVo.setUsername(user.getUsername());
        postVo.setAvatar(user.getAvatar());
        postVo.setNickName(user.getNickname());
        postVo.setOtherUserId(user.getUserId());
        postVo.setTime(post.getUpdateDate());

        redisUtils.hPut(PlatformConstant.POST_LIST_KEY, String.valueOf(post.getId()), JSON.toJSONString(post));

        try {
            esService.addData(postVo);
        } catch (Exception e) {
            throw new CommonException(Constant.ES_ERROR);
        }

        return post.getId();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long updatePost(PostDTO postDTO) {
        Post post = postMapper.getById(postDTO.getId());
        post.setCategoryId(postDTO.getCategoryId());
        post.setCategoryPid(postDTO.getCategoryPid());
        post.setContent(postDTO.getContent());
        post.setCount(postDTO.getCount());
        post.setStatus(postDTO.getStatus());
        post.setCover(postDTO.getCover());
        post.setImages(postDTO.getImgsUrl());

        postMapper.updateById(post);

        //删除原有的绑定关系
        if (postDTO.getAlbum() != null) {
            Album album = albumMapper.getById(postDTO.getAlbum().getId());
            album.setImgCount(album.getImgCount() - postDTO.getCount());
            albumMapper.updateById(album);
            AlbumRelationDTO albumRelationDTO = new AlbumRelationDTO();
            albumRelationDTO.setAid(postDTO.getAlbum().getId());
            albumRelationDTO.setMid(postDTO.getId());
            albumRelationService.deleteAlbumRelation(albumRelationDTO);
        }

        Album album = albumMapper.getById(postDTO.getAlbumId());
        album.setImgCount(postDTO.getCount() + album.getImgCount());
        albumMapper.updateById(album);

        //插入新的绑定关系
        AlbumRelation albumRelation = new AlbumRelation();
        albumRelation.setAid(postDTO.getAlbumId());
        albumRelation.setMid(post.getId());
        albumRelation.setSort(0);
        albumRelationMapper.insert(albumRelation);

        //修改标签
        tagRelationMapper.removeByMid(post.getId());
        List<TagRelation> tagRelationList = new ArrayList<>();

        //当前图片绑定了哪些标签
        for (Tag tag : postDTO.getTags()) {
            long id = tagMapper.getByName(tag.getName()).getId();
            TagRelation tagRelationEntity = new TagRelation();
            tagRelationEntity.setMid(post.getId());
            tagRelationEntity.setTid(id);
            tagRelationList.add(tagRelationEntity);
        }
        tagRelationMapper.insertBatch(tagRelationList);

        PostVo postVo = ConvertUtils.sourceToTarget(post, PostVo.class);
        User user = userMapper.getUserByUserId(post.getUserId());
        postVo.setUsername(user.getUsername());
        postVo.setAvatar(user.getAvatar());
        postVo.setNickName(user.getNickname());
        postVo.setOtherUserId(user.getUserId());
        postVo.setTime(post.getUpdateDate());


        redisUtils.hDelete(PlatformConstant.POST_LIST_KEY, String.valueOf(post.getId()));
        redisUtils.hPut(PlatformConstant.POST_LIST_KEY, String.valueOf(post.getId()), JSON.toJSONString(post));

        String recommendKey = PlatformConstant.RECOMMEND + post.getId();

        if (Boolean.TRUE.equals(redisUtils.hasKey(recommendKey))) {
            redisUtils.delete(recommendKey);
        }

        try {
            esService.update(postVo);
        } catch (Exception e) {
            throw new CommonException(Constant.ES_ERROR);
        }
        return post.getId();
    }

    @Override
    public PageInfo<PostVo> getHot(Integer pageNum, Integer pageSize) {
        PageInfo<PostVo> resPage = new PageInfo<>();
        String key = PlatformConstant.HOT;
        if (Boolean.TRUE.equals(redisUtils.hasKey(key))) {
            String objStr = redisUtils.get(key);
            List<PostVo> postVos = JSON.parseArray(objStr, PostVo.class);
            return PageUtils.getPages(pageNum, pageSize, postVos);
        }

        // 使用 PageHelper 启动分页
        PageHelper.startPage(pageNum, pageSize);
        // 从数据库中获取数据
        List<Post> postList = postMapper.postList(Long.valueOf(pageNum), Long.valueOf(pageSize), 1);
        // 以 agreeCount 值进行排序
        postList.sort((a,b) -> b.getAgreeCount().compareTo(a.getAgreeCount()));
        PageInfo<Post> postsEntityPage = new PageInfo<>(postList);
        List<PostVo> list = new ArrayList<>();
        // 获取所有用户 ID
        List<Long> uids = postList.stream().map(Post::getUserId).collect(Collectors.toList());
        List<User> userList = userMapper.listByIds(uids);
        // 创建用户 ID 到用户对象的映射
        HashMap<Long, User> userMap = new HashMap<>();
        userList.forEach(item -> {
            userMap.put(item.getUserId(), item);
        });

        // 转换 Post 到 PostVo
        PostVo postVo;
        List<String> imgList;
        User userEntity;
        // 遍历帖子，将其映射到 PostVo
        for (Post model : postList) {
            imgList = JSON.parseArray(model.getImages(), String.class);
            userEntity = userMap.get(model.getUserId());
            postVo = ConvertUtils.sourceToTarget(model, PostVo.class);
            postVo.setImages(imgList);
            // 设置用户相关信息
            if (userEntity != null) {
                postVo.setUsername(userEntity.getUsername());
                postVo.setNickName(userEntity.getNickname());
                postVo.setAvatar(userEntity.getAvatar());
            }
            list.add(postVo);
        }
        resPage.setList(list);
        // 设置总记录数
        resPage.setTotal(postsEntityPage.getTotal());
        // 设置总页数
        resPage.setPages(postsEntityPage.getPages());
        // 设置当前页码
        resPage.setPageNum(postsEntityPage.getPageNum());
        // 设置每页记录数
        resPage.setPageSize(postsEntityPage.getPageSize());

        return resPage;
    }

    @Override
    public List<PostVo> getAllBrowseRecordByUser(Long pageNum, Long pageSize, String uid) {
        List<PostVo> postVoList = new ArrayList<>();
        String userBrowseRecordKey = PlatformConstant.BR_IMG_KEY + uid;
        if (Boolean.TRUE.equals(redisUtils.hasKey(userBrowseRecordKey))) {
            List<String> strings = redisUtils.lRange(userBrowseRecordKey, (pageNum - 1) * pageSize, pageNum * pageSize);
            for (String e : strings) {
                postVoList.add(JSON.parseObject(e, PostVo.class));
            }
        }
        return postVoList;
    }

    @Override
    public void delRecord(String uid, List<String> idList) {
        String userBrowseRecordKey = PlatformConstant.BR_IMG_KEY + uid;
        if (Boolean.TRUE.equals(redisUtils.hasKey(userBrowseRecordKey))) {
            List<String> objs = redisUtils.lRange(userBrowseRecordKey, 0, -1);
            for (String mid : idList) {
                for (String s : objs) {
                    PostVo postVo = JSON.parseObject(s, PostVo.class);
                    if (postVo.getId().equals(Long.valueOf(mid))) {
                        redisUtils.lRemove(userBrowseRecordKey, 0, s);
                        break;
                    }
                }
            }
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void addBulkData() {
        List<Post> psotList = postMapper.postList(null,null,1);
        List<PostVo> res = new ArrayList<>();
        PostVo postVo;
        User user;
        List<String> imgList;

        List<Long> uids = psotList.stream().map(Post::getUserId).toList();
        List<User> userList = userMapper.listByIds(uids);
        HashMap<Long, User> userMap = new HashMap<>();
        userList.forEach(item -> {
            userMap.put(item.getUserId(), item);
        });

        for (Post model : psotList) {
            imgList = JSON.parseArray(model.getImages().replace("\\\"", "\""), String.class);
            user = userMap.get(model.getUserId());
            postVo = ConvertUtils.sourceToTarget(model, PostVo.class);
            postVo.setImages(imgList);
            postVo.setUserId(user.getUserId());
            postVo.setOtherUserId(user.getUserId());
            postVo.setUsername(user.getUsername());
            postVo.setNickName(user.getNickname());
            postVo.setAvatar(user.getAvatar());
            postVo.setTime(model.getUpdateDate());
            res.add(postVo);
        }
        try {
            esService.addbulkData(res);
        } catch (Exception e) {
            throw new CommonException(Constant.ES_ERROR);
        }
    }

    @Override
    public void addBulkRedisData() {
        List<Post> postList = postMapper.postList(null,null,1);
        List<Long> uids = postList.stream().map(Post::getUserId).toList();
        List<User> userList = userMapper.listByIds(uids);
        HashMap<Long, User> userMap = new HashMap<>();
        userList.forEach(item -> {
            userMap.put(item.getUserId(), item);
        });
        String key = PlatformConstant.POST_LIST_KEY;
        for (Post model : postList) {
            redisUtils.hPut(key, String.valueOf(model.getId()), JSON.toJSONString(model));
        }
    }
}
